﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Gasco.DataAccess;
using System.Data.Linq;
using Gasco.Business.Workflows;
using Mani.Common;

namespace Gasco.Business.Services
{
   public class LoadingService
    {
       
       public  IList<loading> SearchLoading(string keyword, int pageSize, int pageNumber, string sortBy, string sortDirection)
       {
           var db = DatabaseHelper.GetData();
           IQueryable<loading> result = null;

           if (String.IsNullOrEmpty(keyword))
           {
               result = from l in db.loadings
                        select l;
           }
           else
           {
               result = from l in db.loadings
                        where (l.transportation_type.name.Contains(keyword) || l.order.order_name.Contains(keyword) || l.order.order_number.Contains(keyword) ||
                               l.cmr_number.Contains(keyword) ||
                               l.vessel_number.Contains(keyword))
                        select l;
           }

           if (sortDirection == "descending")
               sortBy = String.Format("{0} DESC", sortBy);

           return result.SortBy<loading>(sortBy).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList<loading>();

       }
       
       public int CountSearchLoading(string keyword)
       {
           var db = DatabaseHelper.GetData();
           IQueryable<loading> result = null;

           if (String.IsNullOrEmpty(keyword))
           {
               result = from l in db.loadings
                        select l;
           }
           else
           {
               result = from l in db.loadings
                        where (l.transportation_type.name.Contains(keyword) || l.order.order_name.Contains(keyword) ||
                              l.cmr_number.Contains(keyword) || l.order.order_number.Contains(keyword) ||
                              l.vessel_number.Contains(keyword))
                        select l;
           }

           return result.Count();
       }

       public loading CreateLoading(loading l)
       {
           l.create_date = DateTime.Now;
           l.update_date = DateTime.Now;
           CheckRules(l);
           return DatabaseHelper.Insert<loading>(l);
       }

       public void UpdateLoading(loading l)
       {
           l.update_date = DateTime.Now;
           CheckRules(l);
           DatabaseHelper.Update<loading>(l);
       }

       public void DeleteLoading(int id)
       {
           loading l = GetLoading(id);
           DatabaseHelper.Delete<loading>(l);
       }

       public loading GetLoading(int id)
       {
           loading result = null;

           using (var db = DatabaseHelper.GetData())
           {
               db.DeferredLoadingEnabled = false;

               result = (from l in db.loadings
                         where (l.id == id)
                         select l).FirstOrDefault<loading>();
           }

           result.SetAsChangeTrackingRoot(true);

           return result;
       }

       public IList<loading> GetLoadingsByOrder(int orderId)
       {
           var db = DatabaseHelper.GetData();
           var result = from l in db.loadings
                    where l.order_id == orderId
                    select l;

           return result.ToList<loading>();
       }

       private bool CheckQuantity(order o, loading l)
       {
           float remainingOrder = RemainLoadingByOrderNum(o.order_number, l.id);

           return l.quantity <= remainingOrder;
       }

       public float RemainLoadingByOrderNum(string orderNum, int excludeLoadingId)
       {
           var db = DatabaseHelper.GetData();

           var loadings =  from l in db.loadings
                           where (l.order.order_number == orderNum && l.id != excludeLoadingId)
                           select l;


           var myOrder =  from o in db.orders
                               where (o.order_number == orderNum)
                               select o;

           if (myOrder.Count() == 0)
               return 0F;

           float totalOrder = myOrder.SingleOrDefault().quantity.Round(3);
           float totalLoadings = 0;

           if (loadings.Count() != 0)
               totalLoadings = loadings.Sum<loading>(l => l.quantity).Round(3);

           return (totalOrder - totalLoadings);

       }
       
       private loading CheckForDuplicate(string crmNumber)
       {
           GascoDBDataContext db = DatabaseHelper.GetData();

           var result = from l in db.loadings
                        where (l.cmr_number == crmNumber)
                        select l;
           return result.FirstOrDefault<loading>();
       }

       private void CheckRules(loading l)
       {
           OrderService orderService = new OrderService();
           order o = orderService.GetOrderById(l.order_id);
           
           
           if (!CheckQuantity(o, l))
               throw new TotalLoadingQuantityMustEqualOrLessThanOrder();

          
           if (o.order_status_id != (int)OrderStates.WaitingForLoading)
               throw new InvalidOrderStatusException();

           
           if (l.loading_date!=null && l.loading_date < o.start_date)
               throw new LoadingDatelessThanOrderStartDate();

           loading result = CheckForDuplicate(l.cmr_number);
           if (result != null && result.id != l.id)
               throw new DuplicateCmrNumber();
           
           if ((l.loading_date == null) && (l.loading_custom_date != null || l.border_arrival_date != null || l.border_departure_date != null || l.offloading_date != null))
               throw new BeforeDateEmpty();

           if ((l.loading_custom_date == null) && (l.border_arrival_date != null || l.border_departure_date != null || l.offloading_date != null))
               throw new BeforeDateEmpty();

           if ((l.border_arrival_date == null) && (l.border_departure_date != null || l.offloading_date != null))
               throw new BeforeDateEmpty();

           if (l.border_departure_date == null && l.offloading_date != null)
               throw new BeforeDateEmpty();

           
           if ((l.loading_custom_date!=null)&&(l.loading_date > l.loading_custom_date) || 
               (l.border_arrival_date!=null)&&(l.loading_date > l.border_arrival_date) ||
               (l.border_departure_date!=null)&&(l.loading_date > l.border_departure_date) ||
               (l.offloading_date!=null)&&(l.loading_date > l.offloading_date) ||
               l.loading_custom_date > l.border_arrival_date ||
               l.loading_custom_date > l.border_departure_date ||
               l.loading_custom_date > l.offloading_date ||
               l.border_arrival_date > l.border_departure_date ||
               l.border_arrival_date > l.offloading_date ||
               l.border_departure_date > l.offloading_date)
               throw new DateMismatch();

         
           
       }
    }
}
